#include "pf_parser.h"
#include "mid_ringbuf.h"
#include "util_api.h"
#include "bw_update_demo.h"

#define HEAD_LEN 5

ringbuf* rx_buf_stream;
int32_t max_frame_len=1024*1024*3;
uint32_t skip_nbyte_find_head=0;
uint32_t frame_cnt = 0;

uint64_t total_rx_dat_len_payload_g = 0;
uint32_t total_rx_pkt_num_payload_g = 0;

int parser_exit=0;

pthread_mutex_t rx_buf_stream_mut=PTHREAD_MUTEX_INITIALIZER;
extern PF_AR8030_RX_THREAD_PARAM_t g_stAr8030RxThread;

static unsigned char buf[FRAME_MAX_LEN];
 

#define DBG_PARSER 0

#define DBG_PARSER_GAP 3000 //ms
static uint32_t total_dat_len=0;
int32_t pretime=0,nowtime=0;
static uint32_t avrg_frame_len=1000;
uint32_t avg_dat_rate=0;
static uint32_t maxframe_len=0;
static uint16_t parser_skip_frm_cnt=0;

PF_PARSER_STATS parser_stats;

void PF_PARSER_Stats_Print()
{
	int i;
	int cnt=0;
	
	printf("parser delay avg=%lu us(100)\n",parser_stats.delay_avg);
	
	printf("parser delay stats:\n");
	for(i=0; i<PARSER_HIST_NUM;i++)
	{
		printf("%2dms,%lu, ",i,parser_stats.delay_stats[i]);
		cnt++;
		if(cnt >= 10)
		{
			printf("\n");
			cnt=0;
		}
	}
	printf("delay > %d ms,%lu\n",PARSER_HIST_NUM,parser_stats.delay_stats[PARSER_HIST_NUM]);
	printf("================================================\n");
	//
	printf("parser intvl jitter stats:\n");
	for(i=0; i<PARSER_HIST_NUM;i++)
	{
		printf("%2dms,%lu ",i,parser_stats.intvl_stats[i]);
		cnt++;
		if(cnt >= 10)
		{
			printf("\n");
			cnt=0;
		}
	}
	printf("intvl > %d ms,%lu\n",PARSER_HIST_NUM,parser_stats.intvl_stats[PARSER_HIST_NUM]);
	printf("================================================\n");
	printf("audio bitrate=%d kbps\n",parser_stats.abr_calc);
}

void PF_Get_Parser_Stats_Str(char *strVbr,char *strAbr)
{
	sprintf(strVbr,"vbr:%d.%d",parser_stats.vbr_calc/1000,parser_stats.vbr_calc%1000);
	sprintf(strAbr,"abr:%d.%d",parser_stats.abr_calc/100,parser_stats.abr_calc%100);
	return ;
}

int PF_Parser_Find_Sync_Head(uint32_t len, int offset)
{
    uint32_t i;
    uint32_t _offset;
    _offset = offset + rx_buf_stream->pread;

	// MID_UTIL_Print_Buf(&rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset)], len>20?20:len);

     for(i=0;i<len-4;i++)
     {
        if( rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset+i)]== 0x00 && \
            rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset+i+1)] == 0x00 && \
            rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset+i+2)] == 0x00 && \
            rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset+i+3)] == 0x01 )
        	{
				if(rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset+i+4)]==0x80)
           		{
           			skip_nbyte_find_head = i;
					rx_buf_stream->pdata[MOD_RINGBUF_LEN(_offset+i+4)];
				    return 0;
           		}
		 	}
     }
    skip_nbyte_find_head = len-4;
    return -1;
}

void PF_Parser_Find_Packet_From_Stream()
{
    uint32_t fifoleavesize=0;
	static  uint32_t prefifoleavesize=0 ;
	static  uint32_t precheck_idex=0 ,check_idex=0;
	int key;
	static uint32_t framelen=0;
	int type;
	pthread_mutex_lock(&rx_buf_stream_mut);
    fifoleavesize = get_leavesave(rx_buf_stream) ;
    pthread_mutex_unlock(&rx_buf_stream_mut);
	
    if(fifoleavesize < SYNC_HEADLEN)
	{
		usleep(100);
		return;
    }
	pthread_mutex_lock(&rx_buf_stream_mut);
    key = PF_Parser_Find_Sync_Head(fifoleavesize,0);
    pthread_mutex_unlock(&rx_buf_stream_mut);
	
    if(key<0)
    {
       pthread_mutex_lock(&rx_buf_stream_mut);
       move_rbuf_len(rx_buf_stream,skip_nbyte_find_head);
       pthread_mutex_unlock(&rx_buf_stream_mut);
	   PRINT_INFO("skip_nbyte_find_head=%u fifoleavesize=%u \n",skip_nbyte_find_head,fifoleavesize);
	   usleep(100);
       return;
    }
	
    if(skip_nbyte_find_head > 0)
    {
    	pthread_mutex_lock(&rx_buf_stream_mut);
		move_rbuf_len(rx_buf_stream,skip_nbyte_find_head);
    	// MID_UTIL_Print_Buf(&rx_buf_stream->pdata[MOD_RINGBUF_LEN(rx_buf_stream->pread)],60);
        PRINT_INFO("frame jump %u delta_check_idex =%u fifoleavesize=%u prefifoleavesize=%u delta_fifoleavesize=%u framelen=%u\r\n",
			skip_nbyte_find_head,check_idex-precheck_idex,fifoleavesize,prefifoleavesize,prefifoleavesize-fifoleavesize,framelen);
			
        pthread_mutex_unlock(&rx_buf_stream_mut);
		prefifoleavesize = fifoleavesize;
		precheck_idex = check_idex;
		
		parser_skip_frm_cnt++;
		if(parser_skip_frm_cnt >= 10)
		{
			parser_skip_frm_cnt = 0;
		}
		usleep(100);
		return;
    }
    if(SYNC_HEADLEN > fifoleavesize-skip_nbyte_find_head)
    {
    	PRINT_INFO("fifoleavesize =%u skip_nbyte_find_head=%u SYNC_HEADLEN=%d  \n",fifoleavesize,skip_nbyte_find_head,SYNC_HEADLEN);
        return;
    }
	pthread_mutex_lock(&rx_buf_stream_mut);
    framelen=   (rx_buf_stream->pdata[MOD_RINGBUF_LEN(rx_buf_stream->pread+HEAD_LEN+0)]<<0)+ \
                (rx_buf_stream->pdata[MOD_RINGBUF_LEN(rx_buf_stream->pread+HEAD_LEN+1)]<<8)+ \
                (rx_buf_stream->pdata[MOD_RINGBUF_LEN(rx_buf_stream->pread+HEAD_LEN+2)]<<16)+ \
                (rx_buf_stream->pdata[MOD_RINGBUF_LEN(rx_buf_stream->pread+HEAD_LEN+3)]<<24);
	type = rx_buf_stream->pdata[MOD_RINGBUF_LEN(rx_buf_stream->pread+HEAD_LEN+5)];
	pthread_mutex_unlock(&rx_buf_stream_mut);
	if(SYNC_HEADLEN +skip_nbyte_find_head+framelen> fifoleavesize)
    {
    	usleep(100);
        return;
    }
	if(framelen==0){
		pthread_mutex_lock(&rx_buf_stream_mut);
		reset_rbuf(rx_buf_stream);
		prefifoleavesize =0;
		fifoleavesize=0;
        //move_rbuf_len(rx_buf_stream,fifoleavesize-skip_nbyte_find_head);
        pthread_mutex_unlock(&rx_buf_stream_mut);
		PRINT_INFO("framelen is %u  \n",framelen);
		usleep(100);
        return;
	}
	
	if(framelen > FRAME_MAX_LEN)
    {
        pthread_mutex_lock(&rx_buf_stream_mut);
        move_rbuf_len(rx_buf_stream,fifoleavesize-skip_nbyte_find_head);
        pthread_mutex_unlock(&rx_buf_stream_mut);
		PRINT_INFO("framelen is too large =%u  \n",framelen);
		usleep(100);
        return;
    }
    if(framelen> (fifoleavesize-skip_nbyte_find_head))
    {
    	usleep(100);
        return;
    }
   
	pthread_mutex_lock(&rx_buf_stream_mut);
	move_rbuf_len(rx_buf_stream,SYNC_HEADLEN);
    read_rbuf(rx_buf_stream,buf,framelen);
	pthread_mutex_unlock(&rx_buf_stream_mut);

	if (type == EVENT_BB_STOP_TEST) {
		parser_exit = 1;
	}
	else {
		total_rx_pkt_num_payload_g++;
		total_rx_dat_len_payload_g+=framelen;
	}
	parser_skip_frm_cnt=0;
}

void PF_Parser_On_Event(void* arg)
{
    if(arg==NULL) return;
	msg_hdr_t* data = (msg_hdr_t*)arg;
    if(data->is_stream)
	{
        pthread_mutex_lock(&rx_buf_stream_mut);
        write_rbuf(rx_buf_stream,(uint8_t*)data->data,data->data_len);
        pthread_mutex_unlock(&rx_buf_stream_mut);
    }
}
int PF_Buf_Write_to_Parser(uint8_t *data, int len)
{
    if(data==NULL) return -1;
    pthread_mutex_lock(&rx_buf_stream_mut);
    write_rbuf(rx_buf_stream,(uint8_t*)data,len);
    pthread_mutex_unlock(&rx_buf_stream_mut);
    return 0;
}

void *PF_Parser_Thread(void* args)
{
	char achName[64];

	//set thread name
	sprintf(achName, "BB_parser");
    prctl(PR_SET_NAME, achName, 0, 0, 0);
	
	while(1)
	{
		if(0==parser_exit)
		{
            PF_Parser_Find_Packet_From_Stream();
		}
		else
		{
			PRINT_INFO("%s exit\n", __FUNCTION__);
			g_stAr8030RxThread.s32Ar8030RxThreadExit = true;
			break;
		}
	}
	return NULL;
}

int PF_Parser_Init(unsigned  int rx_buf_len)
{
	pthread_mutexattr_t attr;
	int s32Ret;

	memset(&parser_stats,0,sizeof(parser_stats));
	
    rx_buf_stream = (ringbuf*)malloc(sizeof(ringbuf));
    if(rbuf_initial(rx_buf_stream,rx_buf_len) < 0)
	{
		return (0);
	}
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
	pthread_mutex_init(&rx_buf_stream_mut, &attr);
	
	
	parser_exit=0;
	s32Ret = MID_UTIL_CreateDetachThread(PF_Parser_Thread,NULL, NULL);
	if(s32Ret < 0)
	{
		PRINT_ERR("PF_Parser_Init fail");
		return -1;
	}
    return 1;
}

void PF_Parser_Deinit()
{
	PRINT_INFO("Parser deinit");
	parser_exit=1;
    rbuf_uninitial(rx_buf_stream);
	free(rx_buf_stream);
	pthread_mutex_destroy(&rx_buf_stream_mut);
}


